home *** CD-ROM | disk | FTP | other *** search
/ PC World 2007 March / PCWorld_2007-03_cd.bin / domacnost a kancelar / scribus / scribus-1.3.3.7-win32-install.exe / lib / bdb.py < prev    next >
Text File  |  2004-11-18  |  21KB  |  612 lines

  1. """Debugger basics"""
  2.  
  3. import sys
  4. import os
  5. import types
  6.  
  7. __all__ = ["BdbQuit","Bdb","Breakpoint"]
  8.  
  9. class BdbQuit(Exception):
  10.     """Exception to give up completely"""
  11.  
  12.  
  13. class Bdb:
  14.  
  15.     """Generic Python debugger base class.
  16.  
  17.     This class takes care of details of the trace facility;
  18.     a derived class should implement user interaction.
  19.     The standard debugger class (pdb.Pdb) is an example.
  20.     """
  21.  
  22.     def __init__(self):
  23.         self.breaks = {}
  24.         self.fncache = {}
  25.  
  26.     def canonic(self, filename):
  27.         if filename == "<" + filename[1:-1] + ">":
  28.             return filename
  29.         canonic = self.fncache.get(filename)
  30.         if not canonic:
  31.             canonic = os.path.abspath(filename)
  32.             canonic = os.path.normcase(canonic)
  33.             self.fncache[filename] = canonic
  34.         return canonic
  35.  
  36.     def reset(self):
  37.         import linecache
  38.         linecache.checkcache()
  39.         self.botframe = None
  40.         self.stopframe = None
  41.         self.returnframe = None
  42.         self.quitting = 0
  43.  
  44.     def trace_dispatch(self, frame, event, arg):
  45.         if self.quitting:
  46.             return # None
  47.         if event == 'line':
  48.             return self.dispatch_line(frame)
  49.         if event == 'call':
  50.             return self.dispatch_call(frame, arg)
  51.         if event == 'return':
  52.             return self.dispatch_return(frame, arg)
  53.         if event == 'exception':
  54.             return self.dispatch_exception(frame, arg)
  55.         if event == 'c_call':
  56.             return self.trace_dispatch
  57.         if event == 'c_exception':
  58.             return self.trace_dispatch
  59.         if event == 'c_return':
  60.             return self.trace_dispatch
  61.         print 'bdb.Bdb.dispatch: unknown debugging event:', repr(event)
  62.         return self.trace_dispatch
  63.  
  64.     def dispatch_line(self, frame):
  65.         if self.stop_here(frame) or self.break_here(frame):
  66.             self.user_line(frame)
  67.             if self.quitting: raise BdbQuit
  68.         return self.trace_dispatch
  69.  
  70.     def dispatch_call(self, frame, arg):
  71.         # XXX 'arg' is no longer used
  72.         if self.botframe is None:
  73.             # First call of dispatch since reset()
  74.             self.botframe = frame.f_back # (CT) Note that this may also be None!
  75.             return self.trace_dispatch
  76.         if not (self.stop_here(frame) or self.break_anywhere(frame)):
  77.             # No need to trace this function
  78.             return # None
  79.         self.user_call(frame, arg)
  80.         if self.quitting: raise BdbQuit
  81.         return self.trace_dispatch
  82.  
  83.     def dispatch_return(self, frame, arg):
  84.         if self.stop_here(frame) or frame == self.returnframe:
  85.             self.user_return(frame, arg)
  86.             if self.quitting: raise BdbQuit
  87.         return self.trace_dispatch
  88.  
  89.     def dispatch_exception(self, frame, arg):
  90.         if self.stop_here(frame):
  91.             self.user_exception(frame, arg)
  92.             if self.quitting: raise BdbQuit
  93.         return self.trace_dispatch
  94.  
  95.     # Normally derived classes don't override the following
  96.     # methods, but they may if they want to redefine the
  97.     # definition of stopping and breakpoints.
  98.  
  99.     def stop_here(self, frame):
  100.         # (CT) stopframe may now also be None, see dispatch_call.
  101.         # (CT) the former test for None is therefore removed from here.
  102.         if frame is self.stopframe:
  103.             return True
  104.         while frame is not None and frame is not self.stopframe:
  105.             if frame is self.botframe:
  106.                 return True
  107.             frame = frame.f_back
  108.         return False
  109.  
  110.     def break_here(self, frame):
  111.         filename = self.canonic(frame.f_code.co_filename)
  112.         if not filename in self.breaks:
  113.             return False
  114.         lineno = frame.f_lineno
  115.         if not lineno in self.breaks[filename]:
  116.             # The line itself has no breakpoint, but maybe the line is the
  117.             # first line of a function with breakpoint set by function name.
  118.             lineno = frame.f_code.co_firstlineno
  119.             if not lineno in self.breaks[filename]:
  120.                 return False
  121.  
  122.         # flag says ok to delete temp. bp
  123.         (bp, flag) = effective(filename, lineno, frame)
  124.         if bp:
  125.             self.currentbp = bp.number
  126.             if (flag and bp.temporary):
  127.                 self.do_clear(str(bp.number))
  128.             return True
  129.         else:
  130.             return False
  131.  
  132.     def do_clear(self, arg):
  133.         raise NotImplementedError, "subclass of bdb must implement do_clear()"
  134.  
  135.     def break_anywhere(self, frame):
  136.         return self.breaks.has_key(
  137.             self.canonic(frame.f_code.co_filename))
  138.  
  139.     # Derived classes should override the user_* methods
  140.     # to gain control.
  141.  
  142.     def user_call(self, frame, argument_list):
  143.         """This method is called when there is the remote possibility
  144.         that we ever need to stop in this function."""
  145.         pass
  146.  
  147.     def user_line(self, frame):
  148.         """This method is called when we stop or break at this line."""
  149.         pass
  150.  
  151.     def user_return(self, frame, return_value):
  152.         """This method is called when a return trap is set here."""
  153.         pass
  154.  
  155.     def user_exception(self, frame, (exc_type, exc_value, exc_traceback)):
  156.         """This method is called if an exception occurs,
  157.         but only if we are to stop at or just below this level."""
  158.         pass
  159.  
  160.     # Derived classes and clients can call the following methods
  161.     # to affect the stepping state.
  162.  
  163.     def set_step(self):
  164.         """Stop after one line of code."""
  165.         self.stopframe = None
  166.         self.returnframe = None
  167.         self.quitting = 0
  168.  
  169.     def set_next(self, frame):
  170.         """Stop on the next line in or below the given frame."""
  171.         self.stopframe = frame
  172.         self.returnframe = None
  173.         self.quitting = 0
  174.  
  175.     def set_return(self, frame):
  176.         """Stop when returning from the given frame."""
  177.         self.stopframe = frame.f_back
  178.         self.returnframe = frame
  179.         self.quitting = 0
  180.  
  181.     def set_trace(self, frame=None):
  182.         """Start debugging from `frame`.
  183.  
  184.         If frame is not specified, debugging starts from caller's frame.
  185.         """
  186.         if frame is None:
  187.             frame = sys._getframe().f_back
  188.         self.reset()
  189.         while frame:
  190.             frame.f_trace = self.trace_dispatch
  191.             self.botframe = frame
  192.             frame = frame.f_back
  193.         self.set_step()
  194.         sys.settrace(self.trace_dispatch)
  195.  
  196.     def set_continue(self):
  197.         # Don't stop except at breakpoints or when finished
  198.         self.stopframe = self.botframe
  199.         self.returnframe = None
  200.         self.quitting = 0
  201.         if not self.breaks:
  202.             # no breakpoints; run without debugger overhead
  203.             sys.settrace(None)
  204.             frame = sys._getframe().f_back
  205.             while frame and frame is not self.botframe:
  206.                 del frame.f_trace
  207.                 frame = frame.f_back
  208.  
  209.     def set_quit(self):
  210.         self.stopframe = self.botframe
  211.         self.returnframe = None
  212.         self.quitting = 1
  213.         sys.settrace(None)
  214.  
  215.     # Derived classes and clients can call the following methods
  216.     # to manipulate breakpoints.  These methods return an
  217.     # error message is something went wrong, None if all is well.
  218.     # Set_break prints out the breakpoint line and file:lineno.
  219.     # Call self.get_*break*() to see the breakpoints or better
  220.     # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint().
  221.  
  222.     def set_break(self, filename, lineno, temporary=0, cond = None,
  223.                   funcname=None):
  224.         filename = self.canonic(filename)
  225.         import linecache # Import as late as possible
  226.         line = linecache.getline(filename, lineno)
  227.         if not line:
  228.             return 'Line %s:%d does not exist' % (filename,
  229.                                    lineno)
  230.         if not filename in self.breaks:
  231.             self.breaks[filename] = []
  232.         list = self.breaks[filename]
  233.         if not lineno in list:
  234.             list.append(lineno)
  235.         bp = Breakpoint(filename, lineno, temporary, cond, funcname)
  236.  
  237.     def clear_break(self, filename, lineno):
  238.         filename = self.canonic(filename)
  239.         if not filename in self.breaks:
  240.             return 'There are no breakpoints in %s' % filename
  241.         if lineno not in self.breaks[filename]:
  242.             return 'There is no breakpoint at %s:%d' % (filename,
  243.                                     lineno)
  244.         # If there's only one bp in the list for that file,line
  245.         # pair, then remove the breaks entry
  246.         for bp in Breakpoint.bplist[filename, lineno][:]:
  247.             bp.deleteMe()
  248.         if not Breakpoint.bplist.has_key((filename, lineno)):
  249.             self.breaks[filename].remove(lineno)
  250.         if not self.breaks[filename]:
  251.             del self.breaks[filename]
  252.  
  253.     def clear_bpbynumber(self, arg):
  254.         try:
  255.             number = int(arg)
  256.         except:
  257.             return 'Non-numeric breakpoint number (%s)' % arg
  258.         try:
  259.             bp = Breakpoint.bpbynumber[number]
  260.         except IndexError:
  261.             return 'Breakpoint number (%d) out of range' % number
  262.         if not bp:
  263.             return 'Breakpoint (%d) already deleted' % number
  264.         self.clear_break(bp.file, bp.line)
  265.  
  266.     def clear_all_file_breaks(self, filename):
  267.         filename = self.canonic(filename)
  268.         if not filename in self.breaks:
  269.             return 'There are no breakpoints in %s' % filename
  270.         for line in self.breaks[filename]:
  271.             blist = Breakpoint.bplist[filename, line]
  272.             for bp in blist:
  273.                 bp.deleteMe()
  274.         del self.breaks[filename]
  275.  
  276.     def clear_all_breaks(self):
  277.         if not self.breaks:
  278.             return 'There are no breakpoints'
  279.         for bp in Breakpoint.bpbynumber:
  280.             if bp:
  281.                 bp.deleteMe()
  282.         self.breaks = {}
  283.  
  284.     def get_break(self, filename, lineno):
  285.         filename = self.canonic(filename)
  286.         return filename in self.breaks and \
  287.             lineno in self.breaks[filename]
  288.  
  289.     def get_breaks(self, filename, lineno):
  290.         filename = self.canonic(filename)
  291.         return filename in self.breaks and \
  292.             lineno in self.breaks[filename] and \
  293.             Breakpoint.bplist[filename, lineno] or []
  294.  
  295.     def get_file_breaks(self, filename):
  296.         filename = self.canonic(filename)
  297.         if filename in self.breaks:
  298.             return self.breaks[filename]
  299.         else:
  300.             return []
  301.  
  302.     def get_all_breaks(self):
  303.         return self.breaks
  304.  
  305.     # Derived classes and clients can call the following method
  306.     # to get a data structure representing a stack trace.
  307.  
  308.     def get_stack(self, f, t):
  309.         stack = []
  310.         if t and t.tb_frame is f:
  311.             t = t.tb_next
  312.         while f is not None:
  313.             stack.append((f, f.f_lineno))
  314.             if f is self.botframe:
  315.                 break
  316.             f = f.f_back
  317.         stack.reverse()
  318.         i = max(0, len(stack) - 1)
  319.         while t is not None:
  320.             stack.append((t.tb_frame, t.tb_lineno))
  321.             t = t.tb_next
  322.         return stack, i
  323.  
  324.     #
  325.  
  326.     def format_stack_entry(self, frame_lineno, lprefix=': '):
  327.         import linecache, repr
  328.         frame, lineno = frame_lineno
  329.         filename = self.canonic(frame.f_code.co_filename)
  330.         s = '%s(%r)' % (filename, lineno)
  331.         if frame.f_code.co_name:
  332.             s = s + frame.f_code.co_name
  333.         else:
  334.             s = s + "<lambda>"
  335.         if '__args__' in frame.f_locals:
  336.             args = frame.f_locals['__args__']
  337.         else:
  338.             args = None
  339.         if args:
  340.             s = s + repr.repr(args)
  341.         else:
  342.             s = s + '()'
  343.         if '__return__' in frame.f_locals:
  344.             rv = frame.f_locals['__return__']
  345.             s = s + '->'
  346.             s = s + repr.repr(rv)
  347.         line = linecache.getline(filename, lineno)
  348.         if line: s = s + lprefix + line.strip()
  349.         return s
  350.  
  351.     # The following two methods can be called by clients to use
  352.     # a debugger to debug a statement, given as a string.
  353.  
  354.     def run(self, cmd, globals=None, locals=None):
  355.         if globals is None:
  356.             import __main__
  357.             globals = __main__.__dict__
  358.         if locals is None:
  359.             locals = globals
  360.         self.reset()
  361.         sys.settrace(self.trace_dispatch)
  362.         if not isinstance(cmd, types.CodeType):
  363.             cmd = cmd+'\n'
  364.         try:
  365.             try:
  366.                 exec cmd in globals, locals
  367.             except BdbQuit:
  368.                 pass
  369.         finally:
  370.             self.quitting = 1
  371.             sys.settrace(None)
  372.  
  373.     def runeval(self, expr, globals=None, locals=None):
  374.         if globals is None:
  375.             import __main__
  376.             globals = __main__.__dict__
  377.         if locals is None:
  378.             locals = globals
  379.         self.reset()
  380.         sys.settrace(self.trace_dispatch)
  381.         if not isinstance(expr, types.CodeType):
  382.             expr = expr+'\n'
  383.         try:
  384.             try:
  385.                 return eval(expr, globals, locals)
  386.             except BdbQuit:
  387.                 pass
  388.         finally:
  389.             self.quitting = 1
  390.             sys.settrace(None)
  391.  
  392.     def runctx(self, cmd, globals, locals):
  393.         # B/W compatibility
  394.         self.run(cmd, globals, locals)
  395.  
  396.     # This method is more useful to debug a single function call.
  397.  
  398.     def runcall(self, func, *args, **kwds):
  399.         self.reset()
  400.         sys.settrace(self.trace_dispatch)
  401.         res = None
  402.         try:
  403.             try:
  404.                 res = func(*args, **kwds)
  405.             except BdbQuit:
  406.                 pass
  407.         finally:
  408.             self.quitting = 1
  409.             sys.settrace(None)
  410.         return res
  411.  
  412.  
  413. def set_trace():
  414.     Bdb().set_trace()
  415.  
  416.  
  417. class Breakpoint:
  418.  
  419.     """Breakpoint class
  420.  
  421.     Implements temporary breakpoints, ignore counts, disabling and
  422.     (re)-enabling, and conditionals.
  423.  
  424.     Breakpoints are indexed by number through bpbynumber and by
  425.     the file,line tuple using bplist.  The former points to a
  426.     single instance of class Breakpoint.  The latter points to a
  427.     list of such instances since there may be more than one
  428.     breakpoint per line.
  429.  
  430.     """
  431.  
  432.     # XXX Keeping state in the class is a mistake -- this means
  433.     # you cannot have more than one active Bdb instance.
  434.  
  435.     next = 1        # Next bp to be assigned
  436.     bplist = {}     # indexed by (file, lineno) tuple
  437.     bpbynumber = [None] # Each entry is None or an instance of Bpt
  438.                 # index 0 is unused, except for marking an
  439.                 # effective break .... see effective()
  440.  
  441.     def __init__(self, file, line, temporary=0, cond=None, funcname=None):
  442.         self.funcname = funcname
  443.         # Needed if funcname is not None.
  444.         self.func_first_executable_line = None
  445.         self.file = file    # This better be in canonical form!
  446.         self.line = line
  447.         self.temporary = temporary
  448.         self.cond = cond
  449.         self.enabled = 1
  450.         self.ignore = 0
  451.         self.hits = 0
  452.         self.number = Breakpoint.next
  453.         Breakpoint.next = Breakpoint.next + 1
  454.         # Build the two lists
  455.         self.bpbynumber.append(self)
  456.         if self.bplist.has_key((file, line)):
  457.             self.bplist[file, line].append(self)
  458.         else:
  459.             self.bplist[file, line] = [self]
  460.  
  461.  
  462.     def deleteMe(self):
  463.         index = (self.file, self.line)
  464.         self.bpbynumber[self.number] = None   # No longer in list
  465.         self.bplist[index].remove(self)
  466.         if not self.bplist[index]:
  467.             # No more bp for this f:l combo
  468.             del self.bplist[index]
  469.  
  470.     def enable(self):
  471.         self.enabled = 1
  472.  
  473.     def disable(self):
  474.         self.enabled = 0
  475.  
  476.     def bpprint(self):
  477.         if self.temporary:
  478.             disp = 'del  '
  479.         else:
  480.             disp = 'keep '
  481.         if self.enabled:
  482.             disp = disp + 'yes'
  483.         else:
  484.             disp = disp + 'no '
  485.         print '%-4dbreakpoint    %s at %s:%d' % (self.number, disp,
  486.                              self.file, self.line)
  487.         if self.cond:
  488.             print '\tstop only if %s' % (self.cond,)
  489.         if self.ignore:
  490.             print '\tignore next %d hits' % (self.ignore)
  491.         if (self.hits):
  492.             if (self.hits > 1): ss = 's'
  493.             else: ss = ''
  494.             print ('\tbreakpoint already hit %d time%s' %
  495.                    (self.hits, ss))
  496.  
  497. # -----------end of Breakpoint class----------
  498.  
  499. def checkfuncname(b, frame):
  500.     """Check whether we should break here because of `b.funcname`."""
  501.     if not b.funcname:
  502.         # Breakpoint was set via line number.
  503.         if b.line != frame.f_lineno:
  504.             # Breakpoint was set at a line with a def statement and the function
  505.             # defined is called: don't break.
  506.             return False
  507.         return True
  508.  
  509.     # Breakpoint set via function name.
  510.  
  511.     if frame.f_code.co_name != b.funcname:
  512.         # It's not a function call, but rather execution of def statement.
  513.         return False
  514.  
  515.     # We are in the right frame.
  516.     if not b.func_first_executable_line:
  517.         # The function is entered for the 1st time.
  518.         b.func_first_executable_line = frame.f_lineno
  519.  
  520.     if  b.func_first_executable_line != frame.f_lineno:
  521.         # But we are not at the first line number: don't break.
  522.         return False
  523.     return True
  524.  
  525. # Determines if there is an effective (active) breakpoint at this
  526. # line of code.  Returns breakpoint number or 0 if none
  527. def effective(file, line, frame):
  528.     """Determine which breakpoint for this file:line is to be acted upon.
  529.  
  530.     Called only if we know there is a bpt at this
  531.     location.  Returns breakpoint that was triggered and a flag
  532.     that indicates if it is ok to delete a temporary bp.
  533.  
  534.     """
  535.     possibles = Breakpoint.bplist[file,line]
  536.     for i in range(0, len(possibles)):
  537.         b = possibles[i]
  538.         if b.enabled == 0:
  539.             continue
  540.         if not checkfuncname(b, frame):
  541.             continue
  542.         # Count every hit when bp is enabled
  543.         b.hits = b.hits + 1
  544.         if not b.cond:
  545.             # If unconditional, and ignoring,
  546.             # go on to next, else break
  547.             if b.ignore > 0:
  548.                 b.ignore = b.ignore -1
  549.                 continue
  550.             else:
  551.                 # breakpoint and marker that's ok
  552.                 # to delete if temporary
  553.                 return (b,1)
  554.         else:
  555.             # Conditional bp.
  556.             # Ignore count applies only to those bpt hits where the
  557.             # condition evaluates to true.
  558.             try:
  559.                 val = eval(b.cond, frame.f_globals,
  560.                        frame.f_locals)
  561.                 if val:
  562.                     if b.ignore > 0:
  563.                         b.ignore = b.ignore -1
  564.                         # continue
  565.                     else:
  566.                         return (b,1)
  567.                 # else:
  568.                 #   continue
  569.             except:
  570.                 # if eval fails, most conservative
  571.                 # thing is to stop on breakpoint
  572.                 # regardless of ignore count.
  573.                 # Don't delete temporary,
  574.                 # as another hint to user.
  575.                 return (b,0)
  576.     return (None, None)
  577.  
  578. # -------------------- testing --------------------
  579.  
  580. class Tdb(Bdb):
  581.     def user_call(self, frame, args):
  582.         name = frame.f_code.co_name
  583.         if not name: name = '???'
  584.         print '+++ call', name, args
  585.     def user_line(self, frame):
  586.         import linecache
  587.         name = frame.f_code.co_name
  588.         if not name: name = '???'
  589.         fn = self.canonic(frame.f_code.co_filename)
  590.         line = linecache.getline(fn, frame.f_lineno)
  591.         print '+++', fn, frame.f_lineno, name, ':', line.strip()
  592.     def user_return(self, frame, retval):
  593.         print '+++ return', retval
  594.     def user_exception(self, frame, exc_stuff):
  595.         print '+++ exception', exc_stuff
  596.         self.set_continue()
  597.  
  598. def foo(n):
  599.     print 'foo(', n, ')'
  600.     x = bar(n*10)
  601.     print 'bar returned', x
  602.  
  603. def bar(a):
  604.     print 'bar(', a, ')'
  605.     return a/2
  606.  
  607. def test():
  608.     t = Tdb()
  609.     t.run('import bdb; bdb.foo(10)')
  610.  
  611. # end
  612.